package bat.iog.hytool.ftp.demo3;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

//import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
//import org.apache.log4j.Logger;
import sun.net.TelnetInputStream;
import sun.net.TelnetOutputStream;
import sun.net.ftp.FtpClient;

/**
 * Java自带的API对FTP的操作
 * @Title:Ftp.java
 */
public class FTPUtils {
    //private static Logger logger = Logger.getLogger(FTPUtils.class.getName());
    public static final String ftp_IP = "127.0.0.1";
    public static final Integer ftp_port = 21;
    public static final String ftp_user = "user";
    public static final String ftp_psw = "root";
    public static final String ftp_stmlog_path = "/root/stm32log/";
    public static final String ftp_ziplog_path = "/root/ziplog/";
    public static final String ftp_rtud_path = "/root/log/rtud/";
    public static final String ftp_updated_path = "/root/log/updated/";
    //public static final String ftp_path="/";

    public static void main(String args[]) {
        //download from FTP
        downloadFTPFile(ftp_IP, "tt", ftp_user, ftp_psw,"/","",true);
        //upload from FTP
        //uploadFromFTP(ftp_IP,ftp_port,ftp_user,ftp_psw,"/","E://新建文本文档.txt","新建文本文档.txt");
    }
    /**
     * @param url        IP
     * @param port       端口
     * @param username   用户名
     * @param password   密码
     * @param remotePath 服务器上的路径
     * @param fileName   要下载的文件
     * @param localPath  保存到本地的文件
     */
    public static boolean downloadFromFTP(String url, int port, String username, String password, String remotePath,
                                          String fileName, String localPath) {
        boolean success = false;
        FTPClient ftp = new FTPClient();
        InputStream input=null;
        BufferedOutputStream writer=null;
        byte[] by=null;
        try {
            int reply;
            ftp.connect(url, port);
            ftp.connect(url);
            // 如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
            //ftp.login(username, password);// 登录
            ftp.enterLocalPassiveMode();
            ftp.setControlEncoding("gbk");
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return success;
            }
            ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
            FTPFile[] fs = ftp.listFiles(); // 获取当前目录下的所有文件

            for (FTPFile ff : fs) {
                if (new String(ff.getName().getBytes(),"utf-8").equals(fileName)) {
                    //防止出现中文文件名是返回null，强制设置成ISO-8859-1的编码方式进行获取输入流
                    input=ftp.retrieveFileStream("/"+(new String(ff.getName().getBytes("gbk"), "ISO-8859-1")));
                    by=new byte[(int)ff.getSize()];
                    //把文件流保存到byte数组中
                    input.read(by);
                    //文件输出到目标目录，不需要判断本地目录是否有相同文件，会自动覆盖
                    writer=new BufferedOutputStream(new FileOutputStream(localPath+"/"+fileName));
                    writer.write(by);
                    System.out.println("输出指定文件【"+fileName+"】到本地目录："+localPath+"/"+fileName+"成功");
                }
            }
            //断开FTP连接
            ftp.logout();
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            if (ftp.isConnected()) {
                try {
                    if(writer!=null) {
                        writer.close();
                    }
                    if(input!=null) {
                        input.close();
                    }
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return success;
    }

    /**
     * @param url
     * @param fileName
     * @param localPath
     * @return
     */
    public static String downloadFTPFile(String url, String fileName, String username , String password, String remotePath, String localPath, boolean isBreakpointResume) {
        String result = "unFindFile";
        FTPClient ftp = new FTPClient();

        int reply;
        try {
            //1.连接服务器
            ftp.connect(url, ftp_port);
            //2.登录服务器 如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
            ftp.login(ftp_user, ftp_psw);
            ftp.enterLocalPassiveMode();
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            //3.判断登陆是否成功
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                //logger.info( "未连接到" + url + "的FTP，用户名或密码错误");
                ftp.disconnect();
                result = "loginFail";
                return result;
            } else {
                //logger.info("FTP连接成功");
            }
            
            List<FileInfo> fileInfos = new ArrayList<>();
            // 获取文件目录树
            // getFileInfo(fileInfos, ftp, remotePath);
            
            //4.指定要下载的目录
            ftp.changeWorkingDirectory(remotePath); // 转移到FTP服务器目录
            //5.遍历下载的目录
            FTPFile[] fs = ftp.listFiles();

            //FTPFile[] ft = ftp.listDirectories(remotePath);
            
            
            int id = 0;
            for (FTPFile ff : fs) {
                id++;
                FileInfo fileInfo = new FileInfo();
                
                fileInfo.setPid(String.valueOf(id));
                fileInfo.setType(ff.getType());
                fileInfo.setPid("root");
                fileInfo.setName(ff.getName());
                
                // 是文件夹
                if (ff.isDirectory()) {
                    String path = remotePath + "/" + ff.getName();
                    ftp.changeWorkingDirectory(path);
                    //FTPFile[] ft = ftp.listFiles();
                    
                }

                
                //解决中文乱码问题，两次解码
                byte[] bytes = ff.getName().getBytes(StandardCharsets.ISO_8859_1);
                String fn = new String(bytes, StandardCharsets.UTF_8);

                if (fn.equals(fileName)) {
                    //6.写操作，将其写入到本地文件中
                    File localFile = new File(localPath + "/" + ff.getName());
                    //判断文件路径是否存在，不存在创建路径
                    if (!localFile.exists() && !localFile.isDirectory()) {
                        localFile.getParentFile().mkdirs();
                    }
                    if (isBreakpointResume) {
                        Long localSize = localFile.length();
                        Long remoteSize = ff.getSize();
                        if (localSize.equals(remoteSize)) {
                            System.out.println("文件已下载过，无需再下载");
                            result = "success";
                            return result;
                        } else if (localSize > remoteSize) {
                            localFile.delete();
                            localSize = 0L;
                        }
                        ftp.setRestartOffset(localSize);
                    }

                    ftp.setBufferSize(1024);
                    OutputStream is = new FileOutputStream(localFile, true);
                    //ftp.setRestartOffset(localSize);
                    ftp.retrieveFile(ff.getName(), is);
                    is.close();
                    //logger.info("从" + url + "输出指定文件【"+fileName+"】到本地目录："+localPath+"/"+fileName+"成功");
                    result = "success";
                    break;
                }
            }
            ftp.logout();
        } catch (IOException e) {
            result = "downloadFail";
            //logger.info("从" +url+ "输出指定文件【"+fileName+"】" + "失败!");
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    private static void getFileInfo (List<FileInfo> fileInfos, FTPClient ftp, String path, String pid) throws IOException {
        //4.指定要下载的目录
        ftp.changeWorkingDirectory(path); // 转移到FTP服务器目录
        //5.遍历下载的目录
        FTPFile[] fs = ftp.listFiles();

        //List<FileInfo> fileInfos = new ArrayList<>();
        //int id = 0;
        for (FTPFile ff : fs) {
            //id++;
            FileInfo fileInfo = new FileInfo();

            fileInfo.setPid(pid);
            fileInfo.setId("1");
            fileInfo.setPath(path);
            fileInfo.setType(ff.getType());
            fileInfo.setName(ff.getName());
            fileInfos.add(fileInfo);
            // 是文件夹
            if (ff.isDirectory()) {
                String subPath = path + "/" + ff.getName();
                getFileInfo(fileInfos, ftp, subPath, fileInfo.getId());
            }
        }
    }
    
    
    
    
    /**
     * ftp上传单个文件
     *
     * @param ftpIP      ftp地址
     * @param port        端口号
     * @param userName    ftp的用户名
     * @param password    ftp的密码
     * @param directory   上传至ftp的路径名不包括文件名
     * @param localFilePath 要上传的本地文件全路径名
     * @param destName    上传至ftp后存储的文件名
     * @throws IOException
     */
    public static boolean uploadFromFTP(String ftpIP,Integer port,String userName,String password,String directory,String localFilePath,String destName) {


        FTPClient ftpClient = new FTPClient();
        FileInputStream fis = null;
        boolean result = false;
        try {
            ftpClient.connect(ftpIP, port);
            ftpClient.login(userName, password);
            ftpClient.enterLocalPassiveMode();
            // 设置上传目录
            ftpClient.changeWorkingDirectory(directory);
            ftpClient.setBufferSize(1024);
            ftpClient.setConnectTimeout(10*1000);
            ftpClient.setControlEncoding("gbk");
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            //防止出现中文文件名是返回null，强制把文件名设置成ISO-8859-1的编码方式进行删除指定文件
            ftpClient.deleteFile(directory+new String(destName.getBytes("gbk"),"ISO-8859-1"));
            File srcFile = new File(localFilePath);
            fis = new FileInputStream(srcFile);
            //上传到FTP服务器==防止出现中文文件名是返回null，强制把文件名设置成ISO-8859-1的编码方式进行上传
            result = ftpClient.storeFile((directory + new String(destName.getBytes("gbk"),"ISO-8859-1")), fis);

        } catch (NumberFormatException e) {
            System.err.println("FTP端口配置错误:不是数字:");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //IOUtils.closeQuietly(fis);
            try {
                ftpClient.disconnect();
            } catch (IOException e) {
                throw new RuntimeException("关闭FTP连接发生异常！", e);
            }
        }
        return result;
    }
}
